package com.huiquan.zs.service;

import com.huiquan.analysis.constants.AnalysisSentenceConstant;
import com.huiquan.analysis.dao.AnalysisRuleDao;
import com.huiquan.analysis.dao.AnalysisVocabularyDao;
import com.huiquan.analysis.domain.AnalysisRule;
import com.huiquan.analysis.domain.AnalysisSentence;
import com.huiquan.analysis.domain.AnalysisVocabulary;
import com.huiquan.analysis.domain.User;
import com.huiquan.analysis.job.AnalysisInit;
import com.huiquan.analysis.service.AnalysisRuleExecuteService;
import com.huiquan.framework.base.BaseService;
import com.huiquan.framework.base.ReturnCode;
import com.huiquan.framework.base.ReturnData;
import com.huiquan.framework.utils.CollectionUtil;
import com.huiquan.framework.utils.GetListUtil;
import com.huiquan.framework.utils.RespHeaderUtil;
import com.huiquan.framework.utils.ReturnUtil;
import com.huiquan.vocab.constant.VocabConstant;
import com.huiquan.vocab.dao.VocabElementDao;
import com.huiquan.vocab.domain.VocabElementChangeDto;
import com.huiquan.vocab.domain.VocabElementChangeRuleDto;
import com.huiquan.vocab.domain.VocabElementDto;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.*;
import java.util.regex.Pattern;

@Service
public class ZsRuleService extends BaseService {

    @Autowired
    private AnalysisRuleDao analysisRuleDao;
    @Autowired
    private AnalysisRuleExecuteService analysisRuleExecuteService;
    @Autowired
    private AnalysisInit analysisInit;
    @Autowired
    private AnalysisVocabularyDao analysisVocabularyDao;

    @Autowired
    private RedisTemplate<String, List<AnalysisSentence>> redisTemplate;

    /**
     * 主诉得到规则列表
     *
     * @param startStr
     * @param wordKey
     * @return
     */
    public Map<String, Object> zsRuleList(String startStr, String wordKey) {
        int start = startStr == null ? 1 : Integer.parseInt(startStr);
        // 初始化过滤的条件
        Map<String, Object> param = new HashMap<>();
        param.put("wordKey", wordKey);
        param.put("type", "1");
        // 获取数据总量
        int totalSize = analysisRuleDao.retrieveSize(param);

        // 获取翻页相关
        Map<String, Integer> pageNo = GetListUtil.getPageNoMap(totalSize, start);
        int startIndex = pageNo.get("startIndex");

        // 获取列表
        List<AnalysisRule> list = new ArrayList<>();
        if (startIndex < totalSize) {
            param.put("startIndex", startIndex);
            list = analysisRuleDao.retrieveList(param);
        }

        Map<String, Object> map = GetListUtil.getReturnMap2(totalSize, pageNo.get("start"), startIndex,
                pageNo.get("endPage"), list, null);
        return map;
    }

    private int getType(int type, String secondType) {
        if (AnalysisSentenceConstant.TYPE_XBS == type) {
            return AnalysisSentenceConstant.xbsRuleTypeMap.get(secondType);
        }
        return type;
    }

    /**
     * 进入规则编辑画面
     *
     * @param idStr
     * @param vocabulary
     * @return
     */
    public Map<String, Object> zsRulePreEdit(String idStr, String vocabulary) {
        AnalysisRule analysisRule = new AnalysisRule();
        List<AnalysisVocabulary> vocabularyList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();

        if (StringUtils.isEmpty(idStr)) {
            // 新增
            analysisRule.setVocabulary(vocabulary);
            analysisRule.setRuleType(AnalysisRule.RULE_TYPE_SPLIT);

            AnalysisVocabulary init = new AnalysisVocabulary();
            init.setVocabulary(vocabulary);
            vocabularyList.add(init);
        } else {
            // 修改
            Long id = Long.parseLong(idStr);
            analysisRule = analysisRuleDao.retrieveObjectById(id);

            String[] ruleItems = analysisRule.getRule().split(";");
            for (String ruleItem : ruleItems) {
                String[] tmp = ruleItem.split("_", 3);
                if (tmp.length < 3) {
                    continue;
                }
                AnalysisVocabulary init = new AnalysisVocabulary();
                init.setVocabulary(tmp[0]);
                init.setCharacteristic(tmp[1]);
                init.setProperty(tmp[2]);

                vocabularyList.add(init);
            }

            // 如果是修改属性类型，则可能会有修改前属性
            if (AnalysisRule.RULE_TYPE_UPDATE_PROPERTY == analysisRule.getRuleType()) {
                map.put("oldCharacter", analysisRule.getRule().split("_", 3)[1]);
                map.put("oldProperty", analysisRule.getRule().split("_", 3)[2]);
            }

            vocabulary = analysisRule.getVocabulary();
        }

        map.put("vocabulary", vocabulary);
        map.put("vocabularys", vocabularyList);
        map.put("rule", analysisRule);
        map.put("characterMap", AnalysisSentenceConstant.getPropertyMapByType(AnalysisSentenceConstant.CHARACTER_LABEL));
        // 规则不属于主诉,现病史,医学影像
        map.put("propertyMap", AnalysisSentenceConstant.getPropertyMapByTypeAndSecondType(-1, ""));
        return map;
    }

    /**
     * 进行规则编辑（新增or修改）操作
     *
     * @param idStr
     * @param vocabulary
     * @param ruleTypeStr
     * @param rule
     * @param user
     * @return
     * @throws Exception
     */
    public ReturnData zsRuleEdit(String idStr, String vocabulary, String ruleTypeStr, String rule, User user)
            throws Exception {
        Long id = 0l;
        int ruleType = Integer.parseInt(ruleTypeStr);
        // 维护实体
        AnalysisRule analysisRule = new AnalysisRule();
        analysisRule.setVocabulary(vocabulary);
        analysisRule.setRule(rule);
        analysisRule.setRuleType(ruleType);
        analysisRule.setModifierId(user.getUserId());
        analysisRule.setType(1);
        analysisRule.setId(0l);

        // 校验规则相互间是否有冲突
        Map<String, Object> param = new HashMap<>();
        param.put("type", 1);
        param.put("exceptId", idStr);
        List<AnalysisRule> rules = analysisRuleDao.retrieveList(param);
        rules.add(analysisRule);
        String clashMsg = checkRuleClash(rules);

        if (StringUtils.isEmpty(idStr)) {
            // 新增
            id = analysisRuleDao.insert(analysisRule);
        } else {
            // 修改
            id = Long.parseLong(idStr);

            analysisRule.setId(id);
            analysisRuleDao.update(analysisRule);
        }
        // 批量更改状态为未完成的句子
        analysisRuleExecuteService.execute(id, rule, vocabulary, ruleType, 1, user, "");

        // 将近五分钟内的未标注句子进行BME预标注
        List<AnalysisVocabulary> list = analysisVocabularyDao.retrieveUnlabeledVocabularysByLastMin(5, 1);
        LOGGER.info("Get vocabulary success, size=" + list.size());
        analysisInit.doBmeInit(list, 1, null);

        // 将redis中的数据都清除
        redisTemplate.delete(redisTemplate.keys("*"));


        return ReturnUtil.success(clashMsg);
    }

    /**
     * 校验规则
     *
     * @param rules 规则列表
     * @return
     */
    public String checkRuleClash(List<AnalysisRule> rules) {
        StringBuffer returnMsg = new StringBuffer();

        // 遍历所有的规则，一个个校验
        for (AnalysisRule rule : rules) {
            long id = rule.getId();
            int ruleType = rule.getRuleType();

            // 遍历所有对比规则，一个个比较
            for (AnalysisRule compareRule : rules) {
                long compareId = compareRule.getId();
                if (id != compareId) {
                    // 如果被对比的规则是改属的
                    if (AnalysisRule.RULE_TYPE_UPDATE_PROPERTY == ruleType) {
                        checkUpdateClash(returnMsg, rule, compareRule);
                    } else {
                        checkMergeAndSplitClash(returnMsg, rule, compareRule);
                        // checkMergeClash(returnMsg, rule, compareRule);
                    }
                }
            }
        }
        if (returnMsg.length() > 0) {
            returnMsg.insert(0, "以下规则请校验：\n");
        }
        return returnMsg.toString();
    }

    private void checkMergeAndSplitClash(StringBuffer returnMsg, AnalysisRule rule, AnalysisRule compareRule) {
        String mergeVocab = rule.getVocabulary();
        String mergeResult = rule.getRule();

        String compareVocab = compareRule.getVocabulary();
        if (compareVocab.indexOf(mergeVocab) > -1) {
            String[] compareRuleSubs = compareRule.getRule().split(";");
            String temp = "";
            String compareResult = "";
            // 找出对比规则结果中和被对比匹配的
            for (String compareRuleSub : compareRuleSubs) {
                if (temp.isEmpty() && mergeVocab.startsWith(compareRuleSub.split("_")[0])) {
                    temp = compareRuleSub.split("_")[0];
                    compareResult = compareRuleSub + ";";
                } else if (!temp.isEmpty()) {
                    temp += compareRuleSub.split("_")[0];
                    compareResult += compareRuleSub + ";";
                }
                if (!temp.isEmpty() && !mergeVocab.startsWith(temp)) {
                    temp = "";
                    compareResult = "";
                }
                if (mergeVocab.equals(temp)) {
                    if (!mergeResult.equals(compareResult)) {
                        returnMsg.append("(");
                        returnMsg.append(rule.getVocabulary());
                        returnMsg.append(",");
                        returnMsg.append(compareRule.getVocabulary());
                        returnMsg.append(")\n");
                    } else {
                        temp = "";
                        compareResult = "";
                    }
                }
            }
        }
    }

    private void checkUpdateClash(StringBuffer returnMsg, AnalysisRule rule, AnalysisRule compareRule) {
        String rulePatternStr = rule.getVocabulary().replace("_ _", "_.*_").trim();
        if (rulePatternStr.endsWith("_")) {
            rulePatternStr += ".*";
        }
        String ruleResult = rule.getRule();

        // 两个规则进行对比
        String[] compareRuleSubs = compareRule.getRule().split(";");
        for (String compareRuleSub : compareRuleSubs) {
            if (Pattern.matches("^" + rulePatternStr + "$", compareRuleSub)
                    && !ruleResult.equals(compareRuleSub + ";")) {
                returnMsg.append("(");
                returnMsg.append(rule.getVocabulary());
                returnMsg.append(",");
                returnMsg.append(compareRule.getVocabulary());
                returnMsg.append(")\n");
                break;
            }
        }
    }

    public boolean del(String idStr) {
        Long id = Long.parseLong(idStr);
        analysisRuleDao.deleteById(id);

        return true;
    }

    
    @Autowired
    private VocabElementDao vocabElementDao;

    /**
     * 得到规则列表
     *
     * @param startStr
     * @param keyword
     * @param propertyKey
     * @param exactSearchFlag
     * @param checkFlag
     * @return
     */
    public Map<String, Object> checkRuleList(String startStr, String keyword, String propertyKey, String exactSearchFlag,
                                      String checkFlag) {
        LOGGER.info("List start!");
        boolean exactFlag = exactSearchFlag != null && exactSearchFlag.equals("1");

        Map<String, Object> param = new HashMap<>();
        if (keyword != null && !keyword.isEmpty()) {
            param.put("vocabulary", exactFlag ? keyword : "%" + keyword + "%");
        }
        if (StringUtils.isNotBlank(propertyKey)) {
            param.put("property", propertyKey);
        }
        param.put("splitType", "splitVocabulary");
        if (StringUtils.isNotBlank(checkFlag)) {
            param.put("checkFlag", checkFlag);
        }
        int totalSize = vocabElementDao.retrieveDtoSize(param);
        LOGGER.info("List totalSize=" + totalSize);

        Map<String, Integer> pageNo = GetListUtil.getPageNoParam(totalSize, startStr);

        int endPage = pageNo.get("endPage");
        int start = pageNo.get("start");
        int startIndex = pageNo.get("startIndex");

        List<VocabElementDto> list = new ArrayList<>();

        if (startIndex < totalSize) {
            param.put("startIndex", startIndex);
            param.put("orderStr", "t.gmt_modified desc");
            list = vocabElementDao.retrieveDtoList(param);

            LOGGER.info("Get list success!");

            String changes;
            for (VocabElementDto vocabElement : list) {
                String[] sentence = getSentenceAndShowSentence(vocabElement.getSentence());
                vocabElement.setSentence(sentence[0]);
                vocabElement.setShowSentence(sentence[1]);
                changes = vocabElement.getChanges();
                List<VocabElementChangeRuleDto> changeRuleElements = new ArrayList<>();

                VocabElementChangeRuleDto result;
                if (changes != null && !changes.isEmpty()) {
                    String[] changeSplits = changes.split("\\|");
                    for (String changeSplit : changeSplits) {
                        List<VocabElementChangeDto> changeElements = new ArrayList<>();
                        String[] changeValues = changeSplit.split("@");
                        for (String changeValue : changeValues) {
                            VocabElementChangeDto changeElement = new VocabElementChangeDto();
                            changeElement.setrVocabulary(changeValue.split(",")[0]);
                            changeElement.setrProperty(changeValue.split(",")[1]);
                            changeElement.setType(Integer.parseInt(changeValue.split(",")[2]));
                            changeElements.add(changeElement);
                        }
                        result = new VocabElementChangeRuleDto();
                        result.setChangeList(changeElements);
                        changeRuleElements.add(result);
                    }
                } else {
                    VocabElementChangeDto changeElement = new VocabElementChangeDto();
                    List<VocabElementChangeDto> changeElements = new ArrayList<>();
                    changeElement.setrVocabulary(vocabElement.getVocabulary());
                    changeElement.setrProperty(vocabElement.getReplaceProp() == null ? vocabElement.getProperty()
                            : vocabElement.getReplaceProp());
                    changeElement.setType(VocabElementChangeDto.TYPE_SPLIT_NOT_COORDINATE);
                    changeElements.add(changeElement);
                    result = new VocabElementChangeRuleDto();
                    result.setChangeList(changeElements);
                    changeRuleElements.add(result);
                }
                vocabElement.setChangeElements(changeRuleElements);

                String slang = vocabElement.getSlang();
                vocabElement.setSlang(slang != null && slang.isEmpty() ? " " : slang);

            }
        }

        Map<String, Object> map = GetListUtil.getReturnMap2(totalSize, start, startIndex, endPage, list, null);

        Map<String, String> showSearch = new LinkedHashMap<>();
        showSearch.put("keyword", "词语");
        map.put("showSearch", showSearch);
        map.put("propertyList", VocabConstant.elementProperty);

        LOGGER.info("List end!");
        return map;
    }

    /**
     * 根据例句获取在列表上展现的例句内容
     *
     * @param value
     * @return
     */
    private String[] getSentenceAndShowSentence(String value) {
        // 例句的分隔符
        char sentenceSegmentFlag = 3;
        // 例句的频数分割符号
        char countSegmentFlag = 4;
        String[] sentences = value.split("\\" + sentenceSegmentFlag);
        StringBuffer sentence = new StringBuffer();
        for (int i = 0; i < sentences.length; i++) {
            // 去除例句频数
            String[] sentenceAndCount = sentences[i].split("\\" + countSegmentFlag);
            sentences[i] = sentenceAndCount[0];
            sentence.append(sentences[i]);
            if (i != (sentences.length - 1)) {
                sentence.append("\n");
            }
        }
        return new String[]{sentence.toString(), sentences[0]};
    }

    public ReturnData changeCheckFlag(String id, String checkFlag) {
        List<String> ids = new ArrayList<>();
        if (StringUtils.equals("3", checkFlag)) {
            id = id.substring(0, id.length() - 1);
            ids = CollectionUtil.getListByArray(id.split(","));
            checkFlag = "1";
        } else {
            ids.add(id);
        }
        vocabElementDao.changeCheckFlag(ids, checkFlag);
        return ReturnUtil.success();
    }

}
